﻿using System;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Security;
using System.Web;
using log4net;
using log4net.Config;
using Microsoft.Win32;

namespace PD.Web
{
    /// <summary>
    /// Represents a class that logs the exceptions.
    /// </summary>
    public sealed class Logger
    {
        /// <summary>
        /// An instance of the logger.
        /// </summary>
        private static ILog logger;

        /// <summary>
        /// Prevents a default instance of the <see cref="Logger"/> class from being created.
        /// </summary>
        private Logger()
        {
        }

        /// <summary>
        /// Gets the instance of the logger.
        /// </summary>
        public static ILog Instance
        {
            get
            {
                if (logger == null)
                {
                    logger = LogManager.GetLogger(typeof(Logger));
                    StartLogging();
                }

                return logger;
            }
        }

        /// <summary>
        /// Starts the logging.
        /// </summary>
        private static void StartLogging()
        {
            XmlConfigurator.Configure();
            LogVersion();
            LogTimeZone();
            LogAddress();
            LogIISVersion();
            LogOperatingSystem();
            LogIdentity();
        }

        /// <summary>
        /// Logs the version.
        /// </summary>
        private static void LogVersion()
        {
            Instance.Info(string.Format(
                CultureInfo.CurrentCulture,
                Resources.ClientVersion,
                Assembly.GetExecutingAssembly().GetName().Version));
        }

        /// <summary>
        /// Logs the time zone.
        /// </summary>
        private static void LogTimeZone()
        {
            string info = string.Format(
                CultureInfo.CurrentCulture,
                Resources.ClientTimeZone,
                new string[2] { TimeZone.CurrentTimeZone.StandardName, TimeZone.CurrentTimeZone.GetUtcOffset(DateTime.Now).ToString() });
            Instance.Info(info);
        }

        /// <summary>
        /// Logs the address.
        /// </summary>
        private static void LogAddress()
        {
            HttpContext currentContext = null;
            if ((currentContext = GetCurrentContext()) != null)
            {
                string info = string.Format(
                    CultureInfo.CurrentCulture,
                    Resources.ClientAddress,
                    currentContext.Request.Url.GetLeftPart(UriPartial.Authority));
                Instance.Info(info);
            }
        }

        /// <summary>
        /// Logs the IIS version.
        /// </summary>
        private static void LogIISVersion()
        {
            const string IISVersionRegistryKey = @"SYSTEM\CurrentControlSet\Services\W3SVC\Parameters";
            const string MajorVersionKey = "MajorVersion";
            const string MinorVersionKey = "MinorVersion";

            try
            {
                RegistryKey rk = Registry.LocalMachine.OpenSubKey(IISVersionRegistryKey);
                if (rk == null)
                {
                    Instance.Info(Resources.GetIISVersionFailed);
                    return;
                }

                object majorVersion = rk.GetValue(MajorVersionKey);
                object minorVersion = rk.GetValue(MinorVersionKey);
                rk.Close();

                if (majorVersion != null && minorVersion != null)
                {
                    Instance.Info(string.Format(CultureInfo.CurrentCulture, Resources.IISVersion, majorVersion, minorVersion));
                }
                else
                {
                    Instance.Info(Resources.GetIISVersionFailed);
                }
            }
            catch (Exception ex)
            {
                if (ex is SecurityException ||
                    ex is ObjectDisposedException ||
                    ex is IOException ||
                    ex is UnauthorizedAccessException)
                {
                    Instance.Info(Resources.GetIISVersionFailed, ex);
                }

                throw;
            }
        }

        /// <summary>
        /// Logs the operating system.
        /// </summary>
        private static void LogOperatingSystem()
        {
            string info = string.Format(
                CultureInfo.CurrentCulture,
                Resources.OperatingSystemVersionString,
                Environment.OSVersion.VersionString);
            Instance.Info(info);
        }

        /// <summary>
        /// Logs the current identity.
        /// </summary>
        private static void LogIdentity()
        {
            string fullIdentity = null;
            try
            {
                fullIdentity = string.Format(
                    CultureInfo.InvariantCulture,
                    "{0}\\{1}",
                    Environment.UserDomainName,
                    Environment.UserName);
            }
            catch (NotSupportedException)
            {
                fullIdentity = Environment.UserName;
            }

            Instance.Info(string.Format(CultureInfo.CurrentCulture, Resources.CurrentIdentity, fullIdentity));
        }

        /// <summary>
        /// Gets the current context.
        /// </summary>
        /// <returns>
        /// The current context.
        /// </returns>
        private static HttpContext GetCurrentContext()
        {
            if (HttpContext.Current != null && HttpContext.Current.Session != null)
            {
                return HttpContext.Current;
            }

            return null;
        }
    }
}